package com.google.code.mamule.order;

import com.google.code.mamule.integration.Endpoint;
import com.google.code.mamule.integration.Message;
import com.google.code.mamule.mail.Mail;
import com.google.code.mamule.mail.MailRepository;
import com.google.code.mamule.mail.MailStatus;
import com.google.code.mamule.price.PriceRepository;
import com.google.code.mamule.user.ActiveUser;
import com.google.code.mamule.user.User;
import com.google.common.collect.ImmutableSet;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.net.URI;
import java.util.Date;
import java.util.Set;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

/**
 * Created with IntelliJ IDEA. User: borck_000 ; Date: 12/24/13 ; Time: 1:23 PM
 */
@Component
@Path("/user/orders")
@Produces(MediaType.APPLICATION_JSON)
@Transactional
public class OrderEndpoint {

  private final OrderRepository orders;
  private final MailRepository mails;
  private final PriceRepository prices;
  private final ActiveUser active;

  private final OrderProcessor processor;

  @Autowired
  public OrderEndpoint(final OrderRepository orders, final MailRepository mails,
                       final ActiveUser active, final OrderProcessor processor,
                       final PriceRepository prices) {
    this.orders = orders;
    this.mails = mails;
    this.active = active;
    this.processor = processor;
    this.prices = prices;
  }

  @GET
  public Iterable<Order> fetchAll() {
    return orders.findAllFrom(active.get());
  }

  @POST
  public Response create(@Context UriInfo uri) {
    Order created = new Order();
    created.setOwner(active.get());
    created.setDate(new Date());
    created.setTotal(BigDecimal.ZERO);
//    created.setTotal(
//        new BigDecimal(mails.count() * prices.findLatestPrice().getPrice().doubleValue()));
    created = orders.save(created);
    final URI link = uri.getAbsolutePathBuilder().path(created.getId().toString()).build();
    return Response
        .created(link)
        .entity(Message.info(created.getId().toString()))
        .build();
  }

  @GET
  @Path("/{order-id}")
  public Order fetchBy(@PathParam("order-id") Long id) {
    Order found = orders.findByIdAndOwner(id, active.get());
    return Endpoint.failIfNull(found, "you have no order with id %s", id);
  }

  @PUT
  @Path("/{order-id}")
  public Response updateItems(@PathParam("order-id") Long id, OrderItems itemRefs) {
    Order current = orders.findByIdAndOwner(id, active.get());
    Set<Mail> items = ImmutableSet.copyOf(mails.findAll(itemRefs.getItems()));
    checkIfAllMailsEligibleForAttaching(items, active.get());
    current.getItems().clear();
    current.getItems().addAll(items);
    // TODO should calculate new price based on mail items!
    return Response.ok(Message.info("updated order %s", id)).build();
  }

  private void checkIfAllMailsEligibleForAttaching(Iterable<Mail> mails, User owner) {
    for (Mail each : mails) {
      failIfNotOwner(each, owner);
      failIfNotTransient(each);
    }
  }

  private void failIfNotTransient(Mail mail) {
    if (MailStatus.TRANSIENT != mail.getStatus()) {
      Response resp = Response.status(Response.Status.BAD_REQUEST)
          .entity(
              Message.error("cannot attach mail with state %s to another order", mail.getStatus()))
          .build();
      throw new WebApplicationException(resp);
    }
  }

  private void failIfNotOwner(Mail mail, User owner) {
    if (mail.getOwner() != owner) {
      Response resp = Response
          .status(Response.Status.BAD_REQUEST)
          .entity(
              Message
                  .error("cannot add mail %s to your order : you are not the owner of that mail",
                         mail.getId()))
          .build();
      throw new WebApplicationException(resp);
    }
  }

  @POST
  @Path("/{order-id}/confirm")
  public Response confirm(@PathParam("order-id") Long id) {
    Order current = orders.findByIdAndOwner(id, active.get());
    Endpoint.failIfNull(current, "you have no order with id %s", id);
    processor.process(current);
    return Response.accepted(Message.info("order %s confirmed", id)).build();
  }
}
